package com.flot.yazb.widget.utils;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

import com.google.gson.Gson;

/**
 * RSA非对称加密算法
 * 
 * @author chongwenjun
 *
 */
public class RSAUtil {
	/**
	 * 公钥常量
	 */
	public static final String RSA_PUBLIC_KEY = "RSA_PUBLIC_KEY";

	/**
	 * 私钥钥常量
	 */
	public static final String RSA_PRIVATE_KEY = "RSA_PRIVATE_KEY";

	/**
	 * 签名算法
	 */
	public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

	/**
	 * 默认字符集编码UTF-8
	 */
	public static final String DEFAULT_CHAR_UTF_8 = "utf-8";

	/**
	 * 内部keyInfo对象
	 * 
	 * @author chongwenjun
	 *
	 */
	public class KeyInfo {
		// 公钥
		private String publicKey;
		// 私钥
		private String privateKey;

		public KeyInfo() {
			this.publicKey = "";
			this.privateKey = "";
		}

		public String getPublicKey() {
			return publicKey;
		}

		public void setPublicKey(String publicKey) {
			this.publicKey = publicKey;
		}

		public String getPrivateKey() {
			return privateKey;
		}

		public void setPrivateKey(String privateKey) {
			this.privateKey = privateKey;
		}

	}

	/**
	 * 创建RSA密钥配对
	 * 
	 * @return KeyInfo
	 */
	public static KeyInfo createKeyPairs() {
		KeyInfo keyInfo = new RSAUtil().new KeyInfo();
		try {
			// create the keys
			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
			// 初始化密钥对生成器，密钥大小为96-1024位
			keyPairGen.initialize(1024, new SecureRandom());
			// 生成一个密钥对，保存在keyPair中
			KeyPair keyPair = keyPairGen.generateKeyPair();
			// 得到私钥
			RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
			// 得到公钥
			RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

			keyInfo.setPrivateKey(new String(Base64.encodeBase64(privateKey.getEncoded())));
			keyInfo.setPublicKey(new String(Base64.encodeBase64(publicKey.getEncoded())));
			return keyInfo;
		} catch (Exception e) {
			e.printStackTrace();
			return keyInfo;
		}
	}

	/**
	 * 从字符串中加载公钥
	 * 
	 * @param publicKeyStr
	 *            公钥数据字符串
	 * @retrun RSAPublicKey
	 */
	public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr) {
		try {
			byte[] buffer = Base64.decodeBase64(publicKeyStr);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
			return (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 从字符串中加载私钥
	 * 
	 * @param privateKeyStr
	 *            私钥数据字符串
	 * @retrun RSAPrivateKey
	 */
	public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr) {
		try {
			byte[] buffer = Base64.decodeBase64(privateKeyStr);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 公钥加密过程
	 * 
	 * publicKeyEncode方法对应privateKeyDecode方法
	 * 
	 * @param publicKey
	 *            公钥
	 * @param plainTextData
	 *            明文数据
	 * @return
	 * @throws Exception
	 *             加密过程中的异常信息
	 */
	public static byte[] publicKeyEncode(RSAPublicKey publicKey, byte[] plainTextData) {
		if (publicKey == null) {
			return null;
		}
		Cipher cipher = null;
		try {
			// 使用默认RSA
			cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] output = cipher.doFinal(plainTextData);
			return output;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 公钥解密过程
	 * 
	 * privateKeyEncode方法对应publicKeyDecode方法
	 * 
	 * @param publicKey
	 *            公钥
	 * @param cipherData
	 *            密文数据
	 * @return 明文
	 * @throws Exception
	 *             解密过程中的异常信息
	 */
	// public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData) {
	public static byte[] publicKeyDecode(RSAPublicKey publicKey, byte[] cipherData) {
		if (publicKey == null) {
			return null;
		}
		Cipher cipher = null;
		try {
			// 使用默认RSA
			cipher = Cipher.getInstance("RSA");
			// cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
			cipher.init(Cipher.DECRYPT_MODE, publicKey);
			byte[] output = cipher.doFinal(cipherData);
			return output;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 私钥加密过程
	 * 
	 * privateKeyEncode方法对应publicKeyDecode方法
	 * 
	 * @param privateKey
	 *            私钥
	 * @param plainTextData
	 *            明文数据
	 * @return
	 * @throws Exception
	 *             加密过程中的异常信息
	 */
	public static byte[] privateKeyEncode(RSAPrivateKey privateKey, byte[] plainTextData) {
		if (privateKey == null) {
			return null;
		}
		Cipher cipher = null;
		try {
			// 使用默认RSA
			cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, privateKey);
			byte[] output = cipher.doFinal(plainTextData);
			return output;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 私钥解密过程
	 * 
	 * publicKeyEncode方法对应privateKeyDecode方法
	 * 
	 * @param privateKey
	 *            私钥
	 * @param cipherData
	 *            密文数据
	 * @return 明文
	 * @throws Exception
	 *             解密过程中的异常信息
	 */
	public static byte[] privateKeyDecode(RSAPrivateKey privateKey, byte[] cipherData) {
		if (privateKey == null) {
			return null;
		}
		Cipher cipher = null;
		try {
			// 使用默认RSA
			cipher = Cipher.getInstance("RSA");
			// cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] output = cipher.doFinal(cipherData);
			return output;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * RSA签名(私钥签名)
	 * 
	 * signByPrivateKey方法对应doCheckByPublicKey方法
	 * 
	 * @param content
	 *            待签名数据
	 * @param privateKey
	 *            私钥
	 * @param encode
	 *            字符集编码
	 * @return 签名值
	 */
	public static String signByPrivateKey(String content, String privateKey, String encode) {
		try {
			PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));

			KeyFactory keyf = KeyFactory.getInstance("RSA");
			PrivateKey priKey = keyf.generatePrivate(priPKCS8);

			java.security.Signature signature = java.security.Signature
					.getInstance(SIGN_ALGORITHMS);

			signature.initSign(priKey);

			if (StringUtils.isEmpty(encode) || StringUtils.isEmpty(encode.trim())) {
				encode = DEFAULT_CHAR_UTF_8;
			}
			signature.update(content.getBytes(encode));

			byte[] signed = signature.sign();

			return Base64.encodeBase64String(signed);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * RSA验签名检查(公钥签名检查)
	 * 
	 * signByPrivateKey方法对应doCheckByPublicKey方法
	 * 
	 * @param content
	 *            待签名数据
	 * @param sign
	 *            签名数据
	 * @param publicKey
	 *            公钥
	 * @param encode
	 *            字符集编码
	 * @return 布尔值
	 */
	public static boolean doCheckByPublicKey(String content, String sign, String publicKey,
			String encode) {
		try {
//			Cipher CheckCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			byte[] encodedKey = Base64.decodeBase64(publicKey);
			PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

			java.security.Signature signature = java.security.Signature
					.getInstance(SIGN_ALGORITHMS);

			signature.initVerify(pubKey);

			if (StringUtils.isEmpty(encode) || StringUtils.isEmpty(encode.trim())) {
				encode = DEFAULT_CHAR_UTF_8;
			}
			signature.update(content.getBytes(encode));

			boolean bverify = signature.verify(Base64.decodeBase64(sign));
			return bverify;

		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * createLinkString 方法
	 * 
	 * @param
	 *            <String, String> sPara 支付参数信息
	 * @return String
	 */
	public static String createLinkString(Map<String, String> params) {

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		StringBuffer sbPreStr = new StringBuffer();
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = params.get(key);
			// 拼接时，不包括最后一个&字符
			if (i == keys.size() - 1) {
				sbPreStr.append(key);
				sbPreStr.append("=");
				sbPreStr.append(value);
			} else {
				sbPreStr.append(key);
				sbPreStr.append("=");
				sbPreStr.append(value);
				sbPreStr.append("&");
			}
		}

		return String.valueOf(sbPreStr);
	}

	/**
	 * 过滤参数列表 除去空值和签名参数
	 *
	 * @param sArray
	 * @return
	 */
	public static Map<String, String> paraFilter(Map<String, String> sArray) {
		Map<String, String> result = new LinkedHashMap<String, String>();

		if (sArray == null || sArray.size() <= 0) {
			return result;
		}
		Iterator<Map.Entry<String, String>> ite = sArray.entrySet().iterator();
		while (ite.hasNext()) {
			Map.Entry<String, String> entry = ite.next();
			String key = entry.getKey();
			String value = entry.getValue();
			if (value == null || value.equals("")
					|| key.equalsIgnoreCase("sign")
					|| key.equalsIgnoreCase("sign_type")) {
				continue;
			}
			result.put(key, value);
		}
		return result;
	}


	/************************************************************/

	public static void main(String[] args) throws Exception {

		KeyInfo keyInfo = createKeyPairs();
		String publicString = keyInfo.getPublicKey();
		String privateString = keyInfo.getPrivateKey();
		Map<String, String> a = new HashMap<String, String>();
		a.put(RSA_PUBLIC_KEY, publicString);
		a.put(RSA_PRIVATE_KEY, privateString);
		System.out.println("公钥Base64编码:" + publicString);
		System.out.println("私钥Base64编码:" + privateString);
		System.out.println(new Gson().toJson(a));
		System.out.println("");
		/************************************************************/
		byte[] b = null;
		String sign = "";
		String msg = "-=+~O(∩_∩)O哈哈~Hello+=-?><,./;':\"\\_)(0987654321`~!@#$%^&*()_+	|";
		System.out.println("");
		/************************************************************/
		// 私钥加密公钥解密
		System.out.println("原文: " + msg);
		System.out.println("");
		sign = signByPrivateKey(msg, keyInfo.getPrivateKey(), "");
		System.out.println("加密: " + sign);
		System.out.println(
				"验证sign数据结果: " + doCheckByPublicKey(msg, sign, keyInfo.getPublicKey(), ""));
		System.out.println("");
		/************************************************************/
		// 私钥加密&公钥解密
		b = privateKeyEncode(loadPrivateKeyByStr(keyInfo.getPrivateKey()), msg.getBytes());
		System.out.println("私钥加密：" + Base64.encodeBase64String(b));
		System.out.println("公钥解密："
				+ new String(publicKeyDecode(loadPublicKeyByStr(keyInfo.getPublicKey()), b)));
		System.out.println("");
		/************************************************************/
		// 公钥加密&私钥解密
		b = publicKeyEncode(loadPublicKeyByStr(keyInfo.getPublicKey()), msg.getBytes());
		System.out.println("公钥加密：" + Base64.encodeBase64String(b));
		System.out.println("私钥解密："
				+ new String(privateKeyDecode(loadPrivateKeyByStr(keyInfo.getPrivateKey()), b)));

		
//		//验证数据
//		String empNo="0000021";
//		String privateKey="MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALSvMZoen0tARCWQ3Tuuhnd+uVEsGFOTM7mJFgiPg61oTpybON2qiLJjvWpUlvcLhZ9FBvkrWK8BfkUGCGs6nP2SOcQc2J/qWYbYIOStXK+qRhW3KiWRFX5lC6e1uV/Uedtm7RDFzfopgr8nWBmpO869BsNhDgVEnD02GxM3OklLAgMBAAECgYBgnOkV8tfUYgnOWHajaf/Gt4EZ8U0UqzpWNAIPE8YiHAsk3C79ACnV0VVAHPkYIhYSAtPmuhHSiibde4tW4uF8IXfol82kIN559GGYOBPOVQiNHkT8X/rJDRNOa9R7xH7iXgXLWpwcYzy3M3KSpJjcrDMmbmyhaj8aehEkl47NaQJBAPG9wKQP0GQ9419XIm4Lc2pqjK562F950zUNYJsuFpunR2GvMlXIT00bW5VBh9PfN24hQB9GXAyvvp/LBnamxKUCQQC/V35t+mgqIxHA+4SmvugwO3ts6bILOY0Efq34AVmfXqiV6jSqoRaCbHDm0vkUAiJ9D2HUuc3Thewx3hFKgUMvAkEA1p121HCxuvzyyqbqCzahTb2wjgrD4+edKgFpXfuJ2MCm78OBdYTzWmpKYXUfKGuIo35jliB6Ak1YeDbf0yD1fQJAMJdEiSNVPpYnVQ3KkxnaFx2T64WxbD5SPHj7LwcQvnModuHCPC6qa7akOUoMbPNZ1M6KNp500amp4MQXOgd3iwJBAK2cVDa3VaVJyAIlR1MfHkDIQjXF28EG/O1/THgkFGAzpiOLDJDJo+wQ1Ngcne3l+WBRaPNtPsRJWInfjt4//3U=";
//        String newEmpNo = Base64.encodeBase64String(RSAUtil.privateKeyEncode(RSAUtil.loadPrivateKeyByStr(privateKey), empNo.getBytes()));
//        System.out.println("编码前："+newEmpNo);
//        try {
//        	newEmpNo=URLEncoder.encode(newEmpNo,CxjCommonConstants.DEFAULT_CHARSET);
//		} catch (UnsupportedEncodingException e) {
//		}
//        System.out.println("编码后："+newEmpNo);
//        try {
//        	newEmpNo=URLDecoder.decode(newEmpNo,CxjCommonConstants.DEFAULT_CHARSET);
//		} catch (UnsupportedEncodingException e) {
//		}
//        System.out.println("解码后："+newEmpNo);
//        String publicKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0rzGaHp9LQEQlkN07roZ3frlRLBhTkzO5iRYIj4OtaE6cmzjdqoiyY71qVJb3C4WfRQb5K1ivAX5FBghrOpz9kjnEHNif6lmG2CDkrVyvqkYVtyolkRV+ZQuntblf1HnbZu0Qxc36KYK/J1gZqTvOvQbDYQ4FRJw9NhsTNzpJSwIDAQAB";
//        String string = new String(RSAUtil.publicKeyDecode(RSAUtil.loadPublicKeyByStr(publicKey),Base64.decodeBase64(newEmpNo)));
//
//        System.out.println(string);

	}
}